#ifndef Scheduler_h
#define Scheduler_h

#include "Process.h"
#include <queue>
#include <map>

// ---------
// Scheduler
// ---------
// Base API for Scheduler
class Scheduler {
	public:
		virtual void AddProcess(Process * p) {};
		virtual Process * GetNextProcess() {};
		virtual bool ShouldPreempt(Process * p) {};
};

// ------------------
// First In First Out
// ------------------
// Runs tasks in the order they were issued.
class FIFO: public Scheduler {
	public:
		void AddProcess(Process * p);
		Process * GetNextProcess();
		bool ShouldPreempt(Process * p);
	private:
		map < unsigned long, queue <Process *> > processQueue;
};

// ------------------
// Shortest Job First
// ------------------
// Runs the shortest available task first.
// First in first out for tasks of the same length.
class SJF: public Scheduler {
	public:
		void AddProcess(Process * p);
		Process * GetNextProcess();
		bool ShouldPreempt(Process * p);
	private:
		map < unsigned long, queue <Process *> > processQueue;
};

// -----------
// Round Robin
// -----------
// Runs tasks in order that they request time.
// Allots up to timeSliceSize of time to each task.
class RR: public Scheduler {
	public:
		RR(unsigned long timeSliceSize);
		void AddProcess(Process * p);
		Process * GetNextProcess();
		bool ShouldPreempt(Process * p);
	private:
		queue <Process *> processQueue;
		unsigned long timeSliceSize;
};

// --------------
// Priority Queue
// --------------
// Runs higher priority tasks before lower.
// First in first out for tasks of the same priority.
class PQ: public Scheduler {
	public:
		void AddProcess(Process * p);
		Process * GetNextProcess();
		bool ShouldPreempt(Process * p);
	private:
		map < unsigned long, queue <Process *> > processQueue;
};

// -----------------------
// Earliest Deadline First
// -----------------------
// Runs process with the earliest deadline first
// First in first out for tasks with the same deadline.
class EDF: public Scheduler {
	public:
		void AddProcess(Process * p);
		Process * GetNextProcess();
		bool ShouldPreempt(Process * p);
	private:
		map < unsigned long, queue <Process *> > processQueue;
};

// --------------------------
// Multi-Level Feedback Queue
// --------------------------
// Multiple queues with the top level having the highest priority.
// If a process runs for the full time allotted it is downgraded.
// If it runs for less time than the next queue up allots it is upgraded.
// Otherwise it stays in the same queue.
class MLFQ: public Scheduler {
	public:
		MLFQ(vector <unsigned long> timeSliceSizes);
		void AddProcess(Process * p);
		Process * GetNextProcess();
		bool ShouldPreempt(Process * p);
	private:
		vector < queue <Process *> > processQueues;
		vector <unsigned long> timeSliceSizes;
};

#endif
